// Copyright Gary Evans 2006-2007.

using System;
using System.Collections.Generic;
using System.Text;

using Taumuon.Jabuka.Physics;
using Collision = Taumuon.Jabuka.Physics.Collision;

namespace Taumuon.Jabuka.MainApp
{
    /// <summary>
    /// Provides shared functionality for scenes.
    /// </summary>
    public abstract class BaseScene : IScene
    {
        #region Object Lifetime

        /// <summary>
        /// Default Constructor
        /// </summary>
        public BaseScene()
        {
            // Initialise the objects.
            ResetScene();
        }

        #endregion Object Lifetime

        #region IScene Implementation

        /// <summary>
        /// The list of objects that will be drawn.
        /// </summary>
        public List<IDrawable> DrawableObjects
        {
            get
            {
                return this.drawableObjects;
            }
        }

        /// <summary>
        /// Resets the Scene to its starting point.
        /// </summary>
        public abstract void ResetScene();

        /// <summary>
        /// Updates all of the objects in the scene with the given time step.
        /// </summary>
        /// <param name="deltaTime">The time step, in seconds.</param>
        public virtual void Update(double deltaTime)
        {
            collisionManager.Update(deltaTime);
        }

        /// <summary>
        /// This should return an array containing 4 entries - the parameters
        ///  to pass into Gl.glrotated (i.e. angle in degrees, then the 3
        ///  values specifying the rotation vector.
        /// If null is returned (or an array of any other size), then no rotation
        ///  occurs.
        /// </summary>
        /// <remarks>
        /// A nasty hack! This will be removed once we include a camera class.
        /// If this returns non-null, then the scene will be rotated.
        /// </remarks>
        public virtual double[] CameraRotation
        {
            get
            {
                return null;
            }
        }

        #endregion IScene Implementation

        #region Protected Member Variables

        /// <summary>
        /// The list of drawable objects.
        /// </summary>
        protected List<IDrawable> drawableObjects = null;

        /// <summary>
        /// The CollisionManager.
        /// </summary>
        protected Collision.CollisionManager collisionManager = null;

        #endregion Private Member Variables

        internal void AddSphere(Density density, Vector initialLocation, Vector initialVelocity,
            double radius, List<Collision.Sphere> spheres, List<IDrawable> drawableObjects)
        {
            Colour colour;
            double densityValue = (int)density;
            switch (density)
            {
                case Density.Low:
                    colour = new Colour(0.0f, 0.0f, 1.0f);
                    break;
                case Density.Medium:
                    colour = new Colour(0.0f, 1.0f, 0.0f);
                    break;
                case Density.High:
                    colour = new Colour(1.0f, 0.0f, 0.0f);
                    break;
                default:
                    colour = new Colour();
                    System.Diagnostics.Debug.Assert(false, "enum value not recognised");
                    break;
            }
            double mass = densityValue * (4.0 / 3.0) * Math.PI * (Math.Pow(radius, 3.0));

            EulerRigidBody sphereRigidBody = new EulerRigidBody(
                initialLocation, initialVelocity, mass);
            Collision.Sphere sphere = new Collision.Sphere(sphereRigidBody, radius);
            spheres.Add(sphere);
            drawableObjects.Add(new Sphere(sphereRigidBody, radius, colour));
        }
    }

    internal enum Density
    {
        Low = 1,
        Medium = 2,
        High = 3
    }
}
